#ifndef __M_EXCHANGE_H__
#define __M_EXCHANGE_H__
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <cassert>
#include <sstream>

namespace mymq
{
    // 交换机数据类
    struct Exchange
    {
        using ptr = std::shared_ptr<Exchange>;
        std::string name; // 交换机名称
        ExchangeType type; // 交换机类型
        bool durable; // 交换机是否持久化标志
        bool auto_delete; // 交换机是否自动删除标志
        google::protobuf::Map<std::string, std::string> args; // 其它参数

        Exchange(){}
        Exchange(const std::string& ename, ExchangeType etype, bool edurable, bool eauto_delete,
                const google::protobuf::Map<std::string, std::string>& eargs)
        : name(ename), type(etype), durable(edurable), auto_delete(eauto_delete), args(eargs)
        {}
        
        // 参数持久化存储格式：key=val&key=val&key=val
        // 内部解析字符串，将参数存储到内部成员中
        void setArgs(const std::string& _args)
        {
            std::vector<std::string> kvs;
            StrHelper::split(_args, "&", kvs);
            // 得到 key=val...
            for (auto& str : kvs)
            {
                int pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args[key] = val;
            }
        }   
        // 将内部参数进行序列化，返回一个字符串
        std::string getArgs()
        {
            std::string ret;
            for (auto it = args.begin(); it != args.end(); ++it)
            {
                ret += it->first + "=" + it->second + "&";
            }
            return ret;
        }
    };

    // 交换机数据持久化管理类
    using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string& dbfile)
        : _sql_helper(dbfile)
        {
            // aaa/bbb/test.db, 数据库创建之前确保父级目录存在
            std::string par_path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(par_path);
            assert(_sql_helper.open()); // 打开数据库，不存在就会创建
            createTable();
        }
        // 创建表
        void createTable()
        {
            #define CREATE_TABLE "create table if not exists exchange_table(\
                                    name varchar(32) primary key,\
                                    type int,\
                                    durable int,\
                                    auto_delete int,\
                                    args varchar(128));"
            bool ret = _sql_helper.exec(CREATE_TABLE, nullptr, nullptr);
            if (ret == false)
            {
                ELOG("创建交换机数据表失败！");
                abort();
            }
        }

        // 删除表
        void removeTable()
        {
            #define DROP_TABLE "drop table if exists exchange_table;"
            bool ret = _sql_helper.exec(DROP_TABLE, nullptr, nullptr);
            if (ret == false)
            {
                ELOG("删除交换机数据表失败！");
                abort();
            }
        }

        // 插入交换机数据
        bool insert(Exchange::ptr& exp)
        {
            std::stringstream ss;
            // 全列插入
            ss << "insert into exchange_table values(";
            ss << "'" << exp->name << "',";
            ss << exp->type << ",";
            ss << exp->durable << ",";
            ss << exp->auto_delete << ",";
            ss << "'" << exp->getArgs() << "');";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        // 删除交换机数据
        void remove(const std::string& name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        // 查询所有交换机数据, 交换机名称-交换机对象
        ExchangeMap recovery()
        {
            std::stringstream ss;
            ss << "select name, type, durable, auto_delete, args from exchange_table;";

            ExchangeMap ret;
            _sql_helper.exec(ss.str(), selectCallBack, &ret);
            return ret;
        }
    private:
        // 写成静态函数，去掉参数中的 this
        static int selectCallBack(void* arg, int numcol, char** row, char** fields)
        {
            ExchangeMap* ret = (ExchangeMap*)arg;
            Exchange::ptr exp = std::make_shared<Exchange>();

            exp->name = row[0];
            exp->type = (ExchangeType)std::stoi(row[1]);
            exp->durable = std::stoi(row[2]);
            exp->auto_delete = std::stoi(row[3]);
            if (row[4]) exp->setArgs(row[4]);

            ret->insert(std::make_pair(exp->name, exp));
            return 0;
        }
    private:
        SqliteHelper _sql_helper;
    };

    // 交换机内存数据管理类
    class ExchangeManager
    {
    public:
        using ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string& dbfile)
        : _mapper(dbfile)
        {
            _exchanges = _mapper.recovery();
        }

        // 声明交换机  存在就OK，不存在就创建
        bool declareExchange(const std::string& name, ExchangeType type, bool durable, bool auto_delete,
            const google::protobuf::Map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 检查交换机是否存在
            if (_exchanges.find(name) != _exchanges.end())
            {
                return true;
            }
            
            // 交换机不存在，需要创建
            Exchange::ptr exp = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
            if (durable == true) 
            {
                bool ret = _mapper.insert(exp);
                if (ret == false) return false;
            }
            _exchanges.insert(std::make_pair(name, exp));
            return true;
        }

        // 删除交换机
        void deleteExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 判断交换机是否存在
            if (_exchanges.find(name) == _exchanges.end()) return;

            if (_exchanges[name]->durable) _mapper.remove(name);
            _exchanges.erase(name);
        }

        // 获取指定交换机
        Exchange::ptr selectExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 判断交换机是否存在
            if (_exchanges.find(name) == _exchanges.end()) return Exchange::ptr();
            return _exchanges[name];
        }

        // 查找交换机是否存在
        bool exists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.find(name) != _exchanges.end();
        }

        // 查询交换机数量
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }

        // 销毁所有交换机数据
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _exchanges.clear();
        }
    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;
        ExchangeMap _exchanges;
    };
}
#endif